﻿#region Using

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Commons.Diagnostics;
using SAPbouiCOM;
using SapFramework.Application;
using SapFramework.Interface.Controls.Menus.Attributes;
using SapFramework.Queries;

#endregion

namespace SapFramework.Interface.Controls.Menus.Base
{
    /// <summary>
    /// Classe que guarda uma referencia para os menus que estão registrados do SAP Business One.
    /// </summary>
    public class MenuManager : Dictionary<string, Menu>
    {
        #region Construtores - Passados para internal para que não se possam criar instâncias desta classe fora desta DLL (em especial, da classe AddOn)

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the default initial capacity, and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( AddOn aAddOn )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.Dictionary`2"/> can contain.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( int capacity, AddOn aAddOn )
            : base( capacity )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the default initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( IEqualityComparer<string> comparer, AddOn aAddOn )
            : base( comparer )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that is empty, has the specified initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.Dictionary`2"/> can contain.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( int capacity, IEqualityComparer<string> comparer, AddOn aAddOn )
            : base( capacity, comparer )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( IDictionary<string, Menu> dictionary, AddOn aAddOn )
            : base( dictionary )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>.
        /// </summary>
        /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        internal MenuManager( IDictionary<string, Menu> dictionary, IEqualityComparer<string> comparer, AddOn aAddOn )
            : base( dictionary, comparer )
        {
            AddOn = aAddOn;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Collections.Generic.Dictionary`2"/> class with serialized data.
        /// </summary>
        /// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object containing the information required to serialize the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param><param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure containing the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Generic.Dictionary`2"/>.</param>
        /// <param name="aAddOn">AddOn ao qual esta coleção de menus pertence.</param>
        protected MenuManager( SerializationInfo info, StreamingContext context, AddOn aAddOn ) : base( info, context )
        {
            AddOn = aAddOn;
        }

        #endregion

        /// <summary>
        /// Referencia para a classe à qual o MenuManager pertence.
        /// </summary>
        public AddOn AddOn { get; private set; }

        /// <summary>
        /// Indexador para facilitar o acesso.
        /// </summary>
        /// <param name="aMenuUniqueId">Código único do menu, ou <see cref="MenuItem.UID"/>.</param>
        /// <returns>O formulário do PadaOne, quando encontrado. Retorna nulo, do contrário.</returns>
        public new Menu this[ string aMenuUniqueId ]
        {
            get { return ContainsKey( aMenuUniqueId ) ? base[aMenuUniqueId] : null; }
        }

        /// <summary>
        /// Passa o método original para protegido, pois não será usado.
        /// </summary>
        /// <param name="aMenuUniqueId">Código único do menu, ou <see cref="MenuItem.UID"/>.</param>
        /// <param name="aMenu">Menu que será adicionado a coleção.</param>
        protected new void Add( string aMenuUniqueId, Menu aMenu )
        {
            base.Add( aMenuUniqueId, aMenu );
        }


        /// <summary>
        /// Adiciona, cria e retorna um novo menu à lista de controle, quando ele ainda não existir.
        /// Retorna um menu existente com aquele código, do contrário.
        /// </summary>
        /// <typeparam name="T">Classe do menu que será criado.</typeparam>
        /// <returns></returns>
        public T Add<T>() where T : Menu
        {
            Type lMenuType = typeof(T);

            MenuTypeAttribute lMenuAttribute = MenuQueries.GetMenuTypeAttribute( lMenuType );

            Contract.Requires.NotNull( () => lMenuAttribute );

            string lMenuUniqueId = lMenuAttribute.Type;

            Menu lMenu = this[lMenuUniqueId];

            if ( lMenu == null )
            {
                lMenu = (Menu)Activator.CreateInstance( lMenuType, new object[] { AddOn, lMenuUniqueId } );

                base.Add( lMenuUniqueId, lMenu );
            }

            return lMenu as T;
        }

        /// <summary>
        /// Método adicional para remover um menu do controle de menus.
        /// </summary>
        /// <param name="aMenu"></param>
        /// <returns></returns>
        public bool Remove( Menu aMenu )
        {
            return base.Remove( aMenu.UID );
        }

        /// <summary>
        /// Método adicional para remover um menu do controle de menus.
        /// </summary>
        /// <param name="aMenu"></param>
        /// <returns></returns>
        public bool Remove<T>() where T : Menu
        {
            Type lMenuType = typeof( T );

            MenuTypeAttribute lMenuAttribute = MenuQueries.GetMenuTypeAttribute( lMenuType );

            Contract.Requires.NotNull( () => lMenuAttribute );

            string lMenuUniqueId = lMenuAttribute.Type;

            return base.Remove( lMenuUniqueId );
        }
    }
}